package com.example.armmvvm.ui.scrollview

import android.util.Log
import android.view.View
import android.view.ViewGroup
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.widget.NestedScrollView
import androidx.recyclerview.widget.RecyclerView
import com.example.armmvvm.R
import com.example.armmvvm.ui.view.AnchorSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior

/**
 *
 * 处理多层嵌套滚动问题
 * 第一层:Behavior
 *      第二层:嵌套滚动View
 *          第三层1:嵌套滚动View
 *          第三层2:嵌套滚动View
 *
 * 解决问题
 * 1,当层级有三层及以上时,并且第二层处于顶部时,Behavior会拦截除第三层及以后层级的向下滚动事件
 * 实现::避免让Behavior消费下拉滚动事件
 * 2,当层级有三层及以上时,并且第二层View不处于底部时,上划时最底层的View会优先消费滚动事件
 * 实现::可以通过[addNoNestedView]使[scrollView]先滚动
 * 如果第二层原来是[NestedScrollView],可以使用[BehaviorNestedScrollView]
 *
 * 第一层:Behavior
 *      第二层1:嵌套滚动View
 *      第二层2:嵌套滚动View
 * 当处于这样层级时,第二层2的View是无法嵌套滚动的,可以考虑使用[NestedScrollFrameLayout]包裹住第二层的两个View解决嵌套滚动问题
 *
 *
 *
 * 包名：com.example.armmvvm.ui.scrollview
 * 文件描述：
 * 创建人：yanghaozhang
 * 创建时间：2023/1/5 11:11
 * 修改人：
 * 修改时间：
 * 修改备注：
 * @Version:1.0
 */
class NestedScrollBehaviorHelper(private val scrollView: ViewGroup) {

    /**
     * View优先滚动
     */
    private val mPriorityList = mutableListOf<View>()

    /**
     * View不嵌套滚动
     */
    private val mNoNestedList = mutableListOf<View>()

    /**
     * View位于界面的底部,需要scroll滚动到底部的时候,才轮到该View滚动
     */
    private val mBottomNestedList = mutableListOf<View>()

    private var mBehaviorView: View? = null

    private val mBehaviorState: Int
        get() {
            if (mBehaviorView == null) {
                mBehaviorView = findParentBehavior(scrollView)
            }
            if (mBehaviorView != null) {
                val behavior = (mBehaviorView?.layoutParams as? CoordinatorLayout.LayoutParams)?.behavior
                if (behavior is AnchorSheetBehavior) {
                    return behavior.state
                } else if (behavior is BottomSheetBehavior) {
                    return behavior.state
                }
            }
            return BottomSheetBehavior.STATE_EXPANDED
        }

    companion object {
        fun addToBottomList(view: View) {
            setTagTrue(view, R.id.behavior_helper_add_bottom_list)
        }

        fun isAddToBottomList(view: View): Boolean {
            return checkIsTagTrue(view, R.id.behavior_helper_add_bottom_list)
        }

        fun addToPriorityList(view: View) {
            setTagTrue(view, R.id.behavior_helper_add_priority_list)
        }

        fun isAddToPriorityList(view: View): Boolean {
            return checkIsTagTrue(view, R.id.behavior_helper_add_priority_list)
        }

        fun addToNoNestedList(view: View) {
            setTagTrue(view, R.id.behavior_helper_add_no_nested_list)
        }

        fun isAddToNoNestedList(view: View): Boolean {
            return checkIsTagTrue(view, R.id.behavior_helper_add_no_nested_list)
        }

        private fun setTagTrue(view: View, tag: Int) {
            view.setTag(tag, true)
        }

        private fun checkIsTagTrue(view: View, tag: Int): Boolean {
            val isAdd = view.getTag(tag)
            if (isAdd == true) {
                view.setTag(tag, false)
                return true
            }
            return false
        }
    }

    /**
     * 0: 不传递滚动了
     * 1: 不向上传递的滚动,执行[handleNestedPreScroll]
     * 2: 向上传递滚动,执行[handleNestedPreScroll]
     */
    fun interceptNestedPreScroll(target: View, dx: Int, dy: Int, consumed: IntArray?): Int {
        if (isAddToBottomList(target) && !mBottomNestedList.contains(target)) {
            mBottomNestedList.add(target)
        }
        if (isAddToPriorityList(target) && !mPriorityList.contains(target)) {
            mPriorityList.add(target)
        }
        if (isAddToNoNestedList(target) && !mNoNestedList.contains(target)) {
            mNoNestedList.add(target)
        }
        if (isNoNestedView(target)) {
            return 0
        }
        if (isPriorityConsume(target, dy.toFloat())) {
            return 0
        }

        // 往下滑,且target可往下滑时,不向上传递的滚动
        if (dy < 0 && target.canScrollVertically(-1)) {
            return 1
        }
        return 2
    }

    fun handleNestedPreScroll(target: View, dx: Int, dy: Int, consumed: IntArray?) {
        if (scrollView !is NestedScrollView) {
            return
        }
        var consumedHandle: IntArray? = consumed
        var dyHandle: Int = dy
        // 向上滑动时,如果target在mBottomNestedList集合中,scrollView.优先滑动到底部
        if (dyHandle > 0 && isNeedToBottomView(target)) {
            if (consumedHandle == null) {
                consumedHandle = IntArray(2)
            }
            // scrollView 滚动
            log("----2")
            dyHandle -= consumedHandle[1]
            val oldScrollY = scrollView.scrollY
            scrollView.scrollBy(0, dyHandle)
            val myConsumed = scrollView.scrollY - oldScrollY
            consumedHandle[1] += myConsumed
        }
    }

    fun interceptNestedPreFling(target: View, velocityX: Float, velocityY: Float): Boolean {
        // 不让Behavior消费Fling
        if (isPriorityConsume(target, velocityY)) {
            return true
        }
        if (isNoNestedView(target)) {
            return true
        }
        return false
    }

    fun handleNestedPreFling(target: View, velocityX: Float, velocityY: Float, consumeFling: Boolean): Boolean {
        if (needDebug) {
            log("onNestedPreFling() called with: target = [$target], velocityX = [$velocityX], velocityY = [$velocityY]")
        }
        var consumeFlingHandle = consumeFling
        if (scrollView !is NestedScrollView) {
            return consumeFlingHandle
        }
        // 在Up点击事件时,NestedScrollView.onInterceptTouchEvent()调用stopNestedScroll(),导致mChildHelper.mNestedScrollingParentTouch为null
        // super.onNestedPreFling返回都为false
        // 对于RecyclerView,只有consumeFling为false,RecyclerView内部才会执行Fling
        if (!consumeFlingHandle && velocityY < 0) {
            // RecyclerView的优化,只要RecyclerView支持滚动,就不会传递Fling
            if (target is RecyclerView && !target.canScrollVertically(-1)) {
                log("----3.2")
                scrollView.fling(velocityY.toInt())
                consumeFlingHandle = true
            } else if (target is NestedScrollView && target.getScrollY() <= 1) {
                log("----4")
                scrollView.fling(velocityY.toInt())
                consumeFlingHandle = true
            }
        } else if (!consumeFlingHandle && velocityY > 0) {
            // 如果NestedScrollView能向上滚动时
            if (isNeedToBottomView(target) && scrollView.canScrollVertically(1) && mBehaviorState == BottomSheetBehavior.STATE_EXPANDED) {
                log("----5")
                scrollView.fling(velocityY.toInt())
                consumeFlingHandle = true
            }
        }
        return consumeFlingHandle
    }

    fun interceptNestedScroll(
        target: View
    ): Boolean {
        return isNoNestedView(target)
    }

    fun interceptNestedFling(target: View): Boolean {
        return isNoNestedView(target)
    }

    //-------------------------------------------------------------

    private fun findParentBehavior(view: View): View? {
        if (view.layoutParams is CoordinatorLayout.LayoutParams) {
            val behavior = (view.layoutParams as CoordinatorLayout.LayoutParams).behavior
            if (behavior != null) {
                return view
            }
        }
        if (view.parent is View) {
            return findParentBehavior(view.parent as View)
        }
        return null
    }

    fun addPriorityView(view: View?): Boolean {
        log("addPriorityView")
        return mPriorityList.add(view!!)
    }

    fun addNoNestedView(view: View?): Boolean {
        log("addNoNestedView")
        return mNoNestedList.add(view!!)
    }

    /**
     * @return true: 由view优先消费滚动事件
     */
    private fun isPriorityConsume(view: View, dy: Float): Boolean {
        return if (mPriorityList.contains(view)) {
            dy < 0 && view.canScrollVertically(-1) || dy > 0 && view.canScrollVertically(1)
        } else false
    }

    /**
     * @return true: view自主滚动
     */
    private fun isNoNestedView(view: View): Boolean {
        return mNoNestedList.contains(view)
    }

    /**
     * @return true: [scrollView]优先滚动到底部,然后才轮到该View,mBottomNestedList一般是设置底部的Recyclerview
     */
    private fun isNeedToBottomView(view: View): Boolean {
        return mBottomNestedList.contains(view)
    }

    fun reset() {
        log("reset")
        mPriorityList.clear()
        mNoNestedList.clear()
    }

    val needDebug: Boolean = false
    val tag = "NestedScrollBehaviorHelper"

    fun log(string: String) {
        if (needDebug) {
            Log.d(tag, string)
        }
    }
}